package alarm

import (
	"context"
	"encoding/json"
	"strconv"
	"strings"
	"time"

	"system-admin/config"
	"system-admin/config/boot"
	"system-admin/config/mysql"
	"system-admin/config/redis"
	"system-admin/internal/app/grpc/client"
	"system-admin/internal/app/grpc/protoc/devicec"
	"system-admin/internal/dal"
	"system-admin/internal/dao"
	"system-admin/internal/define"
	"system-admin/internal/models"

	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"github.com/silenceper/wechat/v2/officialaccount/message"
)

// PushAlarmMsg 推送告警消息
func PushAlarmMsgCrond() {
	type alarmMsgType struct {
		AlarmType int64  `json:"alarm_type"`
		RobotID   string `json:"robot_id"`
		Battery   string `json:"battery"`
		Content   string `json:"content"`
		CreatedAt int64  `json:"created_at"`
	}
	// 遍历从redis队列获取告警消息
	for {
		redisCtx, redisCtxCancel := context.WithTimeout(context.Background(), time.Second*3)
		msgn, err := redis.NewDB().RPop(redisCtx, define.RedisAlarmNotifyList).Result()
		redisCtxCancel()
		if err != nil {
			break
		}
		// 循环分发告警消息
		var alarmMsg alarmMsgType
		err = json.Unmarshal([]byte(msgn), &alarmMsg)
		if err == nil {
			notifyLock := define.RedisAlarmNotifyLock + ":" + alarmMsg.RobotID + ":" + strconv.Itoa(int(alarmMsg.AlarmType))
			ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
			success, _ := redis.NewDB().SetNX(ctx, notifyLock, time.Now().Unix(), time.Minute*3).Result()
			cancel()
			if !success {
				continue
			}
			// 告警详情内容
			detail := define.AlarmType[int(alarmMsg.AlarmType)].Detail
			if alarmMsg.Content != "" {
				detail = alarmMsg.Content
			}
			// 默认保存一条告警记录，关联用户为管理员
			mysql.NewDB().Model(&models.AlarmNotifyRecord{}).Create(&models.AlarmNotifyRecord{
				AlarmType:    int(alarmMsg.AlarmType),
				MerchantID:   "1",
				RobotID:      alarmMsg.RobotID,
				ReceiveUsers: "1",
				PushResult:   0,
				NotifyType:   0,
				Detail:       detail,
			})
			// 获取相关设备及告警类型的规则
			var notifyRules []models.AlarmNotifyRule
			tx := mysql.NewDB().Model(&models.AlarmNotifyRule{})
			tx.Where(
				mysql.NewDB().Model(&models.AlarmNotifyRule{}).
					Where("robot_ids = ?", alarmMsg.RobotID).
					Or("robot_ids LIKE ?", "%,"+alarmMsg.RobotID+",%").
					Or("robot_ids LIKE ?", alarmMsg.RobotID+",%").
					Or("robot_ids LIKE ?", "%,"+alarmMsg.RobotID))
			tx.Where(
				mysql.NewDB().Model(&models.AlarmNotifyRule{}).
					Where("alarm_types = ?", alarmMsg.AlarmType).
					Or("alarm_types LIKE ?", "%,"+strconv.Itoa(int(alarmMsg.AlarmType))+",%").
					Or("alarm_types LIKE ?", strconv.Itoa(int(alarmMsg.AlarmType))+",%").
					Or("alarm_types LIKE ?", "%,"+strconv.Itoa(int(alarmMsg.AlarmType))),
			)
			tx.Find(&notifyRules)

			// 遍历规则，统计指定方式下要发送的人
			notifyTypeUsers := make(map[int]map[string]bool)
			for _, rule := range notifyRules {
				notifyTypes := rule.NotifyTypes
				notifyTypeArr := strings.Split(notifyTypes, ",")
				for _, notifyType := range notifyTypeArr {
					if notifyTypeInt, err := strconv.Atoi(notifyType); err == nil {
						if notifyTypeUsers[notifyTypeInt] == nil {
							notifyTypeUsers[notifyTypeInt] = make(map[string]bool)
						}
						receiveUsers := rule.ReceiveUsers
						receiveUserArr := strings.Split(receiveUsers, ",")
						for _, userID := range receiveUserArr {
							notifyTypeUsers[notifyTypeInt][userID] = true
						}
					}
				}
			}

			// 获取模板内容
			tplID := define.AlarmTypeTpl[int(alarmMsg.AlarmType)]
			// 默认用模板2
			{
				if tplID == 0 {
					tplID = 2
				}
			}
			tpl, ok2 := define.AlarmTpl[tplID]         // 完成模版
			tplLite, ok3 := define.AlarmTplLite[tplID] // 精简模版
			if !ok2 || !ok3 {
				continue
			}
			// 获取设备信息
			deviceDetail := &devicec.DeviceDetailRsp{}
			deviceAdminCli, err := client.GetDeviceAdminClient()
			if err == nil {
				req := &devicec.DeviceDetailReq{RobotId: alarmMsg.RobotID}
				deviceDetail, _ = deviceAdminCli.DeviceDetail(context.Background(), req)
				if deviceDetail.Device == nil {
					deviceDetail.Device = &devicec.Device{}
				}
			}
			// 告警内容
			msgInfo := make(map[string]string)
			firstClass := define.AlarmType[int(alarmMsg.AlarmType)].FirstClass
			secondClass := define.AlarmType[int(alarmMsg.AlarmType)].SecondClass
			msgInfo["first_class"] = define.AlarmFirstClass[firstClass]
			msgInfo["second_class"] = define.AlarmSecondClass[firstClass][secondClass]
			msgInfo["robot_id"] = alarmMsg.RobotID
			deviceTypeName := define.DeviceType[int(deviceDetail.Device.DeviceType)]
			msgInfo["device_type"] = deviceTypeName
			msgInfo["created_at"] = time.Unix(alarmMsg.CreatedAt, 0).Format("2006-01-02 15:04:05")
			msgInfo["alarm_type"] = define.AlarmType[int(alarmMsg.AlarmType)].Name
			msgInfo["duration"] = strconv.Itoa(int(time.Now().Unix()-alarmMsg.CreatedAt) / 60)
			currentMapName := deviceDetail.Device.CurrentMapName
			msgInfo["map"] = currentMapName
			msgInfo["battery"] = alarmMsg.Battery
			// 模版内容替换
			for k, v := range msgInfo {
				tpl = strings.ReplaceAll(tpl, "{"+k+"}", v)
				tplLite = strings.ReplaceAll(tplLite, "{"+k+"}", v)
			}
			if detail != "" {
				tpl = tpl + detail
			}
			// 统一发送
			for notifyType, usersMap := range notifyTypeUsers {
				var userIDs []string
				for userID := range usersMap {
					userIDs = append(userIDs, userID)
				}
				if len(userIDs) <= 0 {
					continue
				}
				var users []models.User
				mysql.NewDB().Model(&models.User{}).Where("id IN ?", userIDs).Find(&users)

				title := "告警通知-" + msgInfo["alarm_type"]
				switch notifyType {
				// 微信
				case 1:
					pushUserResult := 0
					for _, user := range users {
						// 告警接收关闭的跳过
						if user.AlarmReceive == 0 {
							continue
						}
						if user.WechatOpenID == "" {
							continue
						}
						// 生成告警id，用来关联微信通知详情
						alarmRecordID, err := helper.UUID{}.String()
						if err != nil {
							logx.Error(context.Background(), "uuid gen failed")
							continue
						}
						_, err = boot.OfficialAccount.GetTemplate().Send(&message.TemplateMessage{
							ToUser:     user.WechatOpenID,
							TemplateID: "g2mF8nPTxT69p0KvlpQvM0GkO_-SyCjKzwwLWY0Q03g",
							Data: map[string]*message.TemplateDataItem{
								"keyword1": {
									Value: alarmMsg.RobotID,
								},
								"keyword2": {
									Value: tplLite,
								},
								"keyword3": {
									Value: msgInfo["created_at"],
								},
							},
							URL: config.Config.Host + "/system-admin/public/alarm/notify-detail?id=" + alarmRecordID,
						})
						if err == nil {
							pushUserResult = 1
						} else {
							pushUserResult = 2
							logx.Error(context.Background(),
								"wechat push message failed",
								logx.String("userID", user.ID),
								logx.Int("alarmType", int(alarmMsg.AlarmType)),
								logx.Err(err))
						}
						mysql.NewDB().Model(&models.AlarmNotifyRecord{}).Create(&models.AlarmNotifyRecord{
							ID:           alarmRecordID,
							AlarmType:    int(alarmMsg.AlarmType),
							MerchantID:   deviceDetail.Device.MerchantId,
							RobotID:      alarmMsg.RobotID,
							ReceiveUsers: user.ID,
							PushResult:   pushUserResult,
							Detail:       detail,
							NotifyType:   notifyType,
						})
					}
				// 邮件发送
				case 2:
					pushUserResult := make(map[string]int)
					for _, user := range users {
						// 告警接收关闭的跳过
						if user.AlarmReceive == 0 {
							continue
						}
						mailer := helper.NewMailer(
							config.Config.Email.Host,
							config.Config.Email.Port,
							config.Config.Email.Username,
							config.Config.Email.Password,
						)
						if user.Email != "" {
							err := mailer.SendEmail(config.Config.Email.Username, user.Email, title, tpl, "")
							if err == nil {
								pushUserResult[user.ID] = 1
							} else {
								pushUserResult[user.ID] = 2
								logx.Error(context.Background(), "email push message failed", logx.Err(err))
							}
						}
					}
					// 通知记录
					if len(pushUserResult) > 0 {
						for userID, result := range pushUserResult {
							mysql.NewDB().Model(&models.AlarmNotifyRecord{}).Create(&models.AlarmNotifyRecord{
								AlarmType:    int(alarmMsg.AlarmType),
								MerchantID:   deviceDetail.Device.MerchantId,
								RobotID:      alarmMsg.RobotID,
								ReceiveUsers: userID,
								PushResult:   result,
								NotifyType:   notifyType,
							})
						}
					}
				default:
				}
			}
		}

	}
}

// NotifyRecords 通知记录
func NotifyRecords(
	ctx context.Context,
	merchantPath string,
	alarmType string,
	robotID string,
	receiveUser string,
	startTime int64, endTime int64,
	provinceID, cityID, districtID, locationID string, //省市区位置筛选
	page int, limit int,
	notRepeated bool,
) (
	res interface{},
	total int64,
	err error,
) {
	records := []*dao.AlarmNotifyRecord{}
	query := dal.Use(mysql.NewDB())
	query.Transaction(func(tx *dal.Query) error {
		defer func() {
			dao.TempDevice{}.DropTempDevice(ctx, tx)
		}()
		dao.TempDevice{}.CreateTempDevice(ctx, tx)
		records, total, err = dao.AlarmNotifyRecord{}.List(
			ctx,
			tx,
			merchantPath,
			alarmType, robotID, receiveUser,
			startTime, endTime,
			provinceID, cityID, districtID, locationID,
			page, limit, notRepeated)
		return nil
	})
	// 获取用户列表
	// 构建id-username map
	var users []models.User
	mysql.NewDB().Model(&models.User{}).Select("id", "username").Find(&users)
	userIDMap := make(map[string]string)
	for _, user := range users {
		userIDMap[user.ID] = user.Username
	}
	// 增加报警类型，接收用户，通知类型名称
	for index, record := range records {
		var receiveUserNames []string
		// 报警类型名称
		records[index].AlarmTypeName = define.AlarmType[record.AlarmType].Name
		// 通知方式名称
		records[index].NotifyTypeName = define.NotifyType[record.NotifyType]
		// 接收用户姓名
		receiveUserArr := strings.Split(record.ReceiveUsers, ",")
		for _, receiveUser := range receiveUserArr {
			receiveUserNames = append(receiveUserNames, userIDMap[receiveUser])
		}
		records[index].ReceiveUserNames = strings.Join(receiveUserNames, ",")
	}
	return records, total, nil
}
